/**
 * @file lv_port_indev_templ.c
 *
 */

/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 0

/*********************
 *      INCLUDES
 *********************/
#include <lvgl.h>
#include <rtdevice.h>
#include <usbh_core.h>
#include <usbh_hid.h>


/*********************
 *      DEFINES
 *********************/
// #define MY_LOG(...) rt_kprintf(__VA_ARGS__)
#define MY_LOG(...)

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void mouse_init(void);
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);

/**********************
 *  STATIC VARIABLES
 **********************/
lv_indev_t * indev_mouse;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void lv_port_indev_init(void)
{
    /**
     * Here you will find example implementation of input devices supported by LittelvGL:
     *  - Touchpad
     *  - Mouse (with cursor support)
     *  - Keypad (supports GUI usage only with key)
     *  - Encoder (supports GUI usage only with: left, right, push)
     *  - Button (external buttons to press points on the screen)
     *
     *  The `..._read()` function are only examples.
     *  You should shape them according to your hardware
     */

    static lv_indev_drv_t indev_drv;


    /*------------------
     * Mouse
     * -----------------*/

    /*Initialize your mouse if you have*/
    mouse_init();

    /*Register a mouse input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = mouse_read;
    indev_mouse = lv_indev_drv_register(&indev_drv);

    /*Set cursor. For simplicity set a HOME symbol now.*/
    lv_obj_t * mouse_cursor = lv_img_create(lv_scr_act());
    lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);
    lv_indev_set_cursor(indev_mouse, mouse_cursor);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/*------------------
 * Mouse
 * -----------------*/

/*Initialize your mouse*/

USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t hid_buffer[128];
uint8_t hid_type;
uint8_t keycode;
uint8_t buttons;
int16_t x_move, y_move;
uint8_t wheel;
void usbh_hid_callback(void *arg, int nbytes)
{
    /*@tips: 每种鼠标的格式好像都不一样, 需要抓数据分析再组合*/
    struct usbh_hid *hid_class = (struct usbh_hid *)arg;

    if (nbytes >= 7) {  // 确保有7字节数据

        #if 0            
            for (int i = 0; i < nbytes; i++) {
                MY_LOG("0x%02x ", hid_buffer[i]);
            }
            MY_LOG("\n");
        #endif


        #define KEYBOARD 0x00
        #define MOUSE_TYPE1 0x01
        #define MOUSE_TYPE2 0x02

        hid_type = hid_buffer[0];
        buttons = hid_buffer[1];

        // 检测鼠标类型
        if (hid_type == MOUSE_TYPE1) { // 16位鼠标
            x_move = (int16_t)(hid_buffer[3] << 8 | hid_buffer[2]);
            y_move = (int16_t)(hid_buffer[5] << 8 | hid_buffer[4]);
            wheel = hid_buffer[6];
            // 16位符号转换
            x_move = (x_move > 32767) ? (x_move - 65536) : x_move;
            y_move = (y_move > 32767) ? (y_move - 65536) : y_move;
        } 
        else if (hid_type == MOUSE_TYPE2) { // 12位鼠标
            x_move = (int16_t)((hid_buffer[3]&0x0F) << 8 | hid_buffer[2]);
            y_move = (int16_t)(hid_buffer[4] << 4 | (hid_buffer[3]>>4)&0x0F);
            wheel = hid_buffer[5];
            // 12位符号转换
            x_move = (x_move > 2047) ? (x_move - 4096) : x_move;
            y_move = (y_move > 2047) ? (y_move - 4096) : y_move;
        }
        else if (hid_type == KEYBOARD) {  // 键盘数据
            keycode = hid_buffer[2];
        } 

        // 打印调试信息
        if(hid_type == KEYBOARD){
            MY_LOG("Keycode: %02X\n", keycode);
        }
        else{
            MY_LOG("Buttons: %s%s%s | X:%+6d Y:%+6d Wheel:%s\n",
                    (buttons & 0x01)? "L" : "-",  // 左键
                    (buttons & 0x02)? "R" : "-",  // 右键
                    (buttons & 0x04)? "M" : "-",  // 中键
                    x_move, y_move,
                    (wheel == 0xFF)? "Down" : (wheel <= 0x01)? "Up" : "-");
        }
    }
    
    // 重新提交URB
    usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, 
                     hid_class->intin, hid_buffer, 
                     hid_class->intin->wMaxPacketSize, 
                     0, usbh_hid_callback, hid_class);
    usbh_submit_urb(&hid_class->intin_urb);
}

static void usbh_hid_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
    int ret;
    struct usbh_hid *hid_class = (struct usbh_hid *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
    ;

    /* test with only one buffer, if you have more hid class, modify by yourself */

    /* Suggest you to use timer for int transfer and use ep interval */
    usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_buffer, hid_class->intin->wMaxPacketSize, 0, usbh_hid_callback, hid_class);
    ret = usbh_submit_urb(&hid_class->intin_urb);
    if (ret < 0) {
        goto delete;
    }
    // clang-format off
delete:
    usb_osal_thread_delete(NULL);
    // clang-format on
}

void usbh_hid_run(struct usbh_hid *hid_class)
{
    usb_osal_thread_create("usbh_hid", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_hid_thread, hid_class);
}

static void mouse_init(void)
{
    
    /*Your code comes here*/
}

/*Will be called by the library to read the mouse*/
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    /*Get the current x and y coordinates*/
    mouse_get_xy(&data->point.x, &data->point.y);

    /*Get whether the mouse button is pressed or released*/
    if(mouse_is_pressed()) {
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }
}

/*Return true is the mouse button is pressed*/
static bool mouse_is_pressed(void)
{
    /* 检查鼠标按键状态 (左键=0x01, 右键=0x02, 中键=0x04) */
    return (buttons & 0x07) != 0;  // 任意按键按下返回true
}

static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;
    
    /* 更新鼠标位置，增加灵敏度系数 */
    #define MOUSE_SENSITIVITY_X 3  // 灵敏度系数，可根据需要调整(1-5)
    #define MOUSE_SENSITIVITY_Y 4  // 灵敏度系数，可根据需要调整(1-5)

    last_x += x_move * MOUSE_SENSITIVITY_X;
    last_y += y_move * MOUSE_SENSITIVITY_Y;
    
    /* 限制在屏幕范围内 */
    last_x = last_x < 0 ? 0 : (last_x > LCD_W - 1 ? LCD_W - 1 : last_x);
    last_y = last_y < 0 ? 0 : (last_y > LCD_H - 1 ? LCD_H - 1 : last_y);
    
    *x = last_x;
    *y = last_y;
    
    /* 重置位移值 */
    x_move = 0;
    y_move = 0;
}

#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
